Sissejuhatus
Siin praktikumis jätkame ggplot2 võimaluste õppimisega. Selleks, et tööga pihta saaks hakata, loeme sisse vajalikud paketid ja andmestiku.
library(ggplot2)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ tibble 3.1.0 ✓ dplyr 1.0.3
✓ tidyr 1.1.2 ✓ stringr 1.4.0
✓ readr 1.4.0 ✓ forcats 0.5.1
✓ purrr 0.3.4
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
Graafikute annoteerimine ja mugandamine
Graafikute annoteerimine
Telgede ja graafiku annoteerimise viise me oleme juba töö käigus näinud. Paljud asjad saab ära lahendada erinevate skaleerimisfunktsioonide parameetritega. Siiski on paljudele neis olemas ka mugavamad vasted eraldiu funktsioonidega mis hoiavad trükkimist kokku. Neist olulisemad on
ggtitle() - määrame graafiku pealkirja
xlab(), ylab() - telgede pealkirjad
xlim(), ylim() - telgede väärtusvahemiku määramine
Graafikute stiil
Vahest on vaja muuta ggplot2 graafikute üleüldist stiili või mõne elemendi väljanägemist. Näiteks on standardne ggplot2 graafikute taust hall, mis ei ole alati parim lahendus. Seda on lihtne muuta käsuga theme_bw mis teeb tausta valgeks ja muudab ka portsu muude graafiku elementide värve ja kuju. Neid funktsioone on veel, tasub vaadata mida RStudio pakub, kui kirjutada algus theme_ . Veel rohkem erinevaid teemasid on olemas paketis ggthemes või võite proovida näiteks
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme_bw()
Neid funktsioone on veel, tasub vaadata mida RStudio pakub, kui kirjutada algus theme_ . Veel rohkem erinevaid teemasid on olemas paketis ggthemes (https://yutannihilation.github.io/allYourFigureAreBelongToUs/ggthemes/).
Täpsemalt saab muuta konkreetseid elemente käsuga theme. Siin on terve ports parameetreid mis töötavad hierarhiliselt. Olulisemad on toodud järgmisel joonisel.

Nendele saabväärtuseks anda käske element_text, element_line ja element_rect vastavalt parameetri tüübile. Käskude element_* parameetrid vastavad suhteliselt täpselt sarnaste elementide grid paketis kasutatavatele parameetritele. Oluline funktsioon on ka element_blank mis vastava elementi lihtsalt ära kustutab.
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(panel.background = element_rect(fill = "pink"), panel.grid.minor = element_blank())
Väga oluline parameeter käsus theme on ka legend.position. Kui selle väärtuseks on "none" kustutatakse legend ära. Väärtused "left", "right", "top" ja "bottom" käituvad nagu võiks oodata . Andes ette kahe elemendilise vektori paigutab ta legendi graafiku ala sees vastavalt antud koordinaatidele, paralleelselt on hea kasutada ka legend.justification argumenti, mis võimaldab legendi paigutust täpsemalt kontollida.
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(legend.position = "none")
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(legend.position = "bottom")
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = birth_class)) +
geom_point() +
theme(legend.position = c(1,1), legend.justification = c(1, 1))
Ülesanded
- Proovi saavutada umbes järgmine pilt.


Graafikute salvestamine
Grafikuid saab salvestada käsuga ggsave(), Kui ette anda vaid faili nimi, siis salvestab see käsk viimase graafiku, mis sai joonistatud, kusjuures suuruse võtab ta akna järgi ning failitüübi määrab faili nime laiendi järgi. Parameetreid width ja height kasutades on võimalik ära määrata ka täpselt joonise mõõdud (tollides).
ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
geom_point() +
theme(legend.position = c(1,1), legend.justification = c(1, 1))
ggsave("plot1.png")
ggsave("plot1.pdf")
ggsave("plot1_wide.png", width = 10, height = 5)
Erinevate graafikute kokku panemine
Graafikute tahkudeks jagamine toimib väga hästi, kui me tahame ühte tüüpi graafikut jagada mitmeks. Kuid kui me tahame erinevat tüüpi graafikuid erinevatel muutujatel samal pildil kõrvuti näidata, siis sama lähenemine ei tööta. Siin tulevad appi lisapaketid. Näiteks patchwork on üks mis võimaldab ggplot2 graafikuid kokku panna.
Enne, kui läheme patchwork-i enda juurde vaatame ühte kasulikku nippi. Nimelt on võimalik ggplot graafik muutujana salvetada. Joonistatakse see alles siis kui muutuja väärtus on vaja välja trükkida.

Loeme sisse paketi patchwork ja defineerime kolm graafikut mida kombineerima hakata.
library(patchwork)
p1 = ggplot(linnad, aes(x = per_capita_inc)) +
geom_histogram() +
ggtitle("Plot 1")
p2 = ggplot(linnad, aes(x = per_capita_inc, y = unemployment_rate, colour = Poverty_factor)) +
geom_point() +
ggtitle("Plot 2")
p3 = ggplot(linnad, aes(x = State, y = unemployment_rate, fill = State)) +
geom_boxplot() +
ggtitle("Plot 3")
p1

p2

p3

Patchworkis tehakse ka graafikutega “tehteid”. Selleks, et graafikuid kõrvuti panna on tehe |.

Üksteise alla saab panna graafikuid tehtega / .

Tehteid saab ka kombineerida, siis tuleb tähelepanu juhtida tehete järjekorrale


Selleks, et piltide paigutust paremini kontrollida on funktsioon plot_layout, millega saab joonise erinevaid aspekte muuta. Näiteks heights parameeter võimaldab muuta piltide suhtelisi kõrguseid.

Argument widths töötab sama moodi.

Eelmine pilt jäi kole sest vastavate laiustega on graafikute andmeid näitavad paneelid. Kuna kahel graafikul on aga legend, siis nende laiust arvesse ei võeta. Küll aga on võimalik argumendiga guides kõikidelt piltidelt legendid kokku koguda.

Paketis patchwork on veel palju võimalusi ja tasub uurida paketi kodulehte https://github.com/thomasp85/patchwork ja seal viidatud õpetusi.
Ülesanded
- Proovige tekitada järgnev pilt


ggplot2-ga graafikute joonistamise harjutamine
Selle ja eelmise praktikumi põhjal peaks olulisemad oskused ggplot2 kasutamiseks olemas olema. Nüüd proovime neid rakendada, kasutades ka teadmisi teisest loengust, kus sai tutvustatud graafikute valimise põhimõtteid täpsemalt.
Loeme sisse kõigepealt andmestiku, mis kirjeldab siis 2000 inimese kehamassi indekseid ja juhuslikul päeval tehtud sammude arvu. Iga inimese kohta on ka antud sugu, vanus ja vanusegrupp. Loeme andmestiku sisse.
Iga ülesande puhul tasub proovida erinevaid variante ja mõelda milline töötab antud olukorras paremini ja miks. Meeldetuletuseks, siin on olulisemad käsud mida vaja võib minna
geom_point
geom_histogram
geom_bar
geom_boxplot
geom_density
geom_violin
geom_smooth
facet_grid
Ülesanded
Milline tehtud sammude jaotus? Millist geomeetrilist esitust võib selle uurimiseks kasutada?
Milline on tehtud sammude jaotus sugude kaupa? Vihjed:
Kumma soo esindajad teevad mediaanis vähem sammusid?
Tee läbi see sama võrdlus vanusegruppide kaupa. Kas järeldus on sama?
Vaata vanusegruppide arvukust sugude kaupa. Kas jaotus on sarnane või erinev?
Kas vanuse ja tehtud sammude vahel on seos? Kas seos tundub lineaarne?
Milline on seos kehamassi indeksi ja sammude vahel? Kas seos on lineaarne ja või on tegu millegi keerukamaga?
Kodune ülesanne
Meil on andmestik erinevate maailma riikide ning nende sotsiaalsete indeksite kohta. See andmestik on failis countries.RData mis on kaasas praktikumi materjalidega. Sellel andmestikul tuleks uurida küsimust, kas ja milline on seos laste arvul naise kohta (child_per_woman) oodatava elueaga (life_expectancy). Sealjuures tuleks pildil arvesse võtta ka riikide populatsiooni (population_total), maailmajagu (region) ning jaotust sissetuleku järgi (income_groups). Kõik muutujad võib panna ühele pildile või võib kombineerida ka mitmest panellist patchworki kasutades. Kuna andmed on keerukad võib pildi salvestada suuremana (kasutades käsku ggsave ja argumente height ja width), et kõigel vajalikul piisavalt ruumi oleks.
Esitada tuleb graafikut genereeriv kood ja ka mõne lauseline järeldus, mille te pildilt olete välja lugenud.
load("countries.RData", verbose = T)
Loading objects:
countries

Hindame järgnevaid aspekte
Järelduse asjakohasus ja kui lihtne on seda pildiga kokku viia
Graafiku(te) joonistamisel tehtud valikute asjakohasus
Graafilised detailid ja nende valik
Värviskaalad
Diskreetsete muutujate järjekord
Kõik tekstid pildil võiksid olla kergesti loetavad (suurte tähtedega, grammatiliselt korrektsed, piisavalt kirjeldavad)
LS0tCnRpdGxlOiAiUHJha3Rpa3VtIDQgLSBnZ3Bsb3QyIGrDpHRrIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyBTaXNzZWp1aGF0dXMKClNpaW4gcHJha3Rpa3VtaXMgasOkdGthbWUgZ2dwbG90MiB2w7VpbWFsdXN0ZSDDtXBwaW1pc2VnYS4gU2VsbGVrcywgZXQgdMO2w7ZnYSBwaWh0YSBzYWFrcyBoYWthdGEsIGxvZW1lIHNpc3NlIHZhamFsaWt1ZCBwYWtldGlkIGphIGFuZG1lc3Rpa3UuCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCmxvYWQoImxpbm5hZC5SRGF0YSIsIHZlcmJvc2UgPSBUKQpgYGAKCiMjIEdyYWFmaWt1dGUgYW5ub3RlZXJpbWluZSBqYSBtdWdhbmRhbWluZQoKIyMjIEdyYWFmaWt1dGUgYW5ub3RlZXJpbWluZQoKVGVsZ2VkZSBqYSBncmFhZmlrdSBhbm5vdGVlcmltaXNlIHZpaXNlIG1lIG9sZW1lIGp1YmEgdMO2w7Yga8OkaWd1cyBuw6RpbnVkLiBQYWxqdWQgYXNqYWQgc2FhYiDDpHJhIGxhaGVuZGFkYSBlcmluZXZhdGUgc2thbGVlcmltaXNmdW5rdHNpb29uaWRlIHBhcmFtZWV0cml0ZWdhLiBTaWlza2kgb24gcGFsanVkZWxlIG5laXMgb2xlbWFzIGthIG11Z2F2YW1hZCB2YXN0ZWQgZXJhbGRpdSBmdW5rdHNpb29uaWRlZ2EgbWlzIGhvaWF2YWQgdHLDvGtraW1pc3Qga29ra3UuIE5laXN0IG9sdWxpc2VtYWQgb27CoAoKLSAgIGBnZ3RpdGxlKClgIC0gbcOkw6RyYW1lIGdyYWFmaWt1IHBlYWxraXJqYQoKLSAgIGB4bGFiKClgLCBgeWxhYigpYCAtIHRlbGdlZGUgcGVhbGtpcmphZAoKLSAgIGB4bGltKClgLCBgeWxpbSgpYCAtIHRlbGdlZGUgdsOkw6RydHVzdmFoZW1pa3UgbcOkw6RyYW1pbmUKCiMjIyBHcmFhZmlrdXRlIHN0aWlsCgpWYWhlc3Qgb24gdmFqYSBtdXV0YSBgZ2dwbG90MmAgZ3JhYWZpa3V0ZSDDvGxlw7xsZGlzdCBzdGlpbGkgdsO1aSBtw7VuZSBlbGVtZW5kaSB2w6RsamFuw6RnZW1pc3QuIE7DpGl0ZWtzIG9uIHN0YW5kYXJkbmUgYGdncGxvdDJgIGdyYWFmaWt1dGUgdGF1c3QgaGFsbCwgbWlzIGVpIG9sZSBhbGF0aSBwYXJpbSBsYWhlbmR1cy4gU2VkYSBvbiBsaWh0bmUgbXV1dGEga8Okc3VnYSBgdGhlbWVfYndgIG1pcyB0ZWViIHRhdXN0YSB2YWxnZWtzIGphIG11dWRhYiBrYSBwb3J0c3UgbXV1ZGUgZ3JhYWZpa3UgZWxlbWVudGlkZSB2w6RydmUgamEga3VqdS4gTmVpZCBmdW5rdHNpb29uZSBvbiB2ZWVsLCB0YXN1YiB2YWFkYXRhIG1pZGEgUlN0dWRpbyBwYWt1Yiwga3VpIGtpcmp1dGFkYSBhbGd1cyBgdGhlbWVfYCAuIFZlZWwgcm9oa2VtIGVyaW5ldmFpZCB0ZWVtYXNpZCBvbiBvbGVtYXMgcGFrZXRpcyBnZ3RoZW1lcyB2w7VpIHbDtWl0ZSBwcm9vdmlkYSBuw6RpdGVrcwoKYGBge3J9CmdncGxvdChsaW5uYWQsIGFlcyh4ID0gcGVyX2NhcGl0YV9pbmMsIHkgPSB1bmVtcGxveW1lbnRfcmF0ZSwgY29sb3VyID0gYmlydGhfY2xhc3MpKSArCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV9idygpIApgYGAKCk5laWQgZnVua3RzaW9vbmUgb24gdmVlbCwgdGFzdWIgdmFhZGF0YSBtaWRhIFJTdHVkaW8gcGFrdWIsIGt1aSBraXJqdXRhZGEgYWxndXMgYHRoZW1lX2AgLiBWZWVsIHJvaGtlbSBlcmluZXZhaWQgdGVlbWFzaWQgb24gb2xlbWFzIHBha2V0aXMgYGdndGhlbWVzYCAoPGh0dHBzOi8veXV0YW5uaWhpbGF0aW9uLmdpdGh1Yi5pby9hbGxZb3VyRmlndXJlQXJlQmVsb25nVG9Vcy9nZ3RoZW1lcy8+KS4KCmBgYHtyfQpsaWJyYXJ5KGdndGhlbWVzKQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IGJpcnRoX2NsYXNzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfd3NqKCkgCmBgYAoKVMOkcHNlbWFsdCBzYWFiIG11dXRhIGtvbmtyZWV0c2VpZCBlbGVtZW50ZSBrw6RzdWdhIGB0aGVtZWAuIFNpaW4gb24gdGVydmUgcG9ydHMgcGFyYW1lZXRyZWlkIG1pcyB0w7bDtnRhdmFkIGhpZXJhcmhpbGlzZWx0LiBPbHVsaXNlbWFkIG9uIHRvb2R1ZCBqw6RyZ21pc2VsIGpvb25pc2VsLgoKIVtdKGltYWdlcy9TY3JlZW5zaG90IDIwMjEtMDItMjIgYXQgMTAuNTQuMTgucG5nKQoKTmVuZGVsZSBzYWFidsOkw6RydHVzZWtzIGFuZGEga8Okc2tlIGBlbGVtZW50X3RleHRgLCBgZWxlbWVudF9saW5lYCBqYSBgZWxlbWVudF9yZWN0YCB2YXN0YXZhbHQgcGFyYW1lZXRyaSB0w7zDvGJpbGUuIEvDpHNrdWRlIGBlbGVtZW50XypgIHBhcmFtZWV0cmlkIHZhc3RhdmFkIHN1aHRlbGlzZWx0IHTDpHBzZWx0IHNhcm5hc3RlIGVsZW1lbnRpZGUgZ3JpZCBwYWtldGlzIGthc3V0YXRhdmF0ZWxlIHBhcmFtZWV0cml0ZWxlLiBPbHVsaW5lIGZ1bmt0c2lvb24gb24ga2EgZWxlbWVudF9ibGFuayBtaXMgdmFzdGF2YSBlbGVtZW50aSBsaWh0c2FsdCDDpHJhIGt1c3R1dGFiLgoKYGBge3J9CmdncGxvdChsaW5uYWQsIGFlcyh4ID0gcGVyX2NhcGl0YV9pbmMsIHkgPSB1bmVtcGxveW1lbnRfcmF0ZSwgY29sb3VyID0gYmlydGhfY2xhc3MpKSArCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAicGluayIpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKClbDpGdhIG9sdWxpbmUgcGFyYW1lZXRlciBrw6RzdXMgdGhlbWUgb24ga2EgYGxlZ2VuZC5wb3NpdGlvbmAuIEt1aSBzZWxsZSB2w6TDpHJ0dXNla3Mgb24gYCJub25lImAga3VzdHV0YXRha3NlIGxlZ2VuZCDDpHJhLiBWw6TDpHJ0dXNlZCBgImxlZnQiYCwgYCJyaWdodCJgLCBgInRvcCJgIGphIGAiYm90dG9tImAga8OkaXR1dmFkIG5hZ3UgdsO1aWtzIG9vZGF0YSAuIEFuZGVzIGV0dGUga2FoZSBlbGVtZW5kaWxpc2UgdmVrdG9yaSBwYWlndXRhYiB0YSBsZWdlbmRpIGdyYWFmaWt1IGFsYSBzZWVzIHZhc3RhdmFsdCBhbnR1ZCBrb29yZGluYWF0aWRlbGUsIHBhcmFsbGVlbHNlbHQgb24gaGVhIGthc3V0YWRhIGthIGBsZWdlbmQuanVzdGlmaWNhdGlvbmAgYXJndW1lbnRpLCBtaXMgdsO1aW1hbGRhYiBsZWdlbmRpIHBhaWd1dHVzdCB0w6Rwc2VtYWx0IGtvbnRvbGxpZGEuCgpgYGB7cn0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpgYGB7cn0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBiaXJ0aF9jbGFzcykpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCmBgYHtyfQpnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IGJpcnRoX2NsYXNzKSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygxLDEpLCBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMSkpCmBgYAoKIyMjIyDDnGxlc2FuZGVkCgotICAgUHJvb3ZpIHNhYXZ1dGFkYSB1bWJlcyBqw6RyZ21pbmUgcGlsdC4KCiFbXShpbWFnZXMvU2NyZWVuc2hvdCAyMDIxLTAyLTI4IGF0IDE2LjMxLjU0LnBuZykKCmBgYHtyfQpnZ3Bsb3QobGlubmFkLCBhZXMoYmFjaGVsb3IsIGhpZ2hfc2NsLCBjb2xvciA9IGluY29tZV9jbGFzcykpKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkQ3MDAiKSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygxLDAuMzk4KSwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsIDEpLCBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9ImJsYWNrIiwgc2l6ZT0xKSkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpKwogIHNjYWxlX2NvbG91cl9icmV3ZXIodHlwZSA9ICJkaXYiLCBwYWxldHRlID0gMikgCmBgYAoKCiMjIEdyYWFmaWt1dGUgc2FsdmVzdGFtaW5lCgpHcmFmaWt1aWQgc2FhYiBzYWx2ZXN0YWRhIGvDpHN1Z2EgYGdnc2F2ZSgpYCwgS3VpIGV0dGUgYW5kYSB2YWlkIGZhaWxpIG5pbWksIHNpaXMgc2FsdmVzdGFiIHNlZSBrw6RzayB2aWltYXNlIGdyYWFmaWt1LCBtaXMgc2FpIGpvb25pc3RhdHVkLCBrdXNqdXVyZXMgc3V1cnVzZSB2w7V0YWIgdGEgYWtuYSBqw6RyZ2kgbmluZyBmYWlsaXTDvMO8YmkgbcOkw6RyYWIgZmFpbGkgbmltZSBsYWllbmRpIGrDpHJnaS4gUGFyYW1lZXRyZWlkIGB3aWR0aGAgamEgYGhlaWdodGAga2FzdXRhZGVzIG9uIHbDtWltYWxpayDDpHJhIG3DpMOkcmF0YSBrYSB0w6Rwc2VsdCBqb29uaXNlIG3DtcO1ZHVkICh0b2xsaWRlcykuCgpgYGB7cn0KZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBQb3ZlcnR5X2ZhY3RvcikpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMSwxKSwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsIDEpKQoKZ2dzYXZlKCJwbG90MS5wbmciKQpnZ3NhdmUoInBsb3QxLnBkZiIpCmdnc2F2ZSgicGxvdDFfd2lkZS5wbmciLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KQpgYGAKCiMjIEVyaW5ldmF0ZSBncmFhZmlrdXRlIGtva2t1IHBhbmVtaW5lCgpHcmFhZmlrdXRlIHRhaGt1ZGVrcyBqYWdhbWluZSB0b2ltaWIgdsOkZ2EgaMOkc3RpLCBrdWkgbWUgdGFoYW1lIMO8aHRlIHTDvMO8cGkgZ3JhYWZpa3V0IGphZ2FkYSBtaXRtZWtzLiBLdWlkIGt1aSBtZSB0YWhhbWUgZXJpbmV2YXQgdMO8w7xwaSBncmFhZmlrdWlkIGVyaW5ldmF0ZWwgbXV1dHVqYXRlbCBzYW1hbCBwaWxkaWwga8O1cnZ1dGkgbsOkaWRhdGEsIHNpaXMgc2FtYSBsw6RoZW5lbWluZSBlaSB0w7bDtnRhLiBTaWluIHR1bGV2YWQgYXBwaSBsaXNhcGFrZXRpZC4gTsOkaXRla3MgYHBhdGNod29ya2Agb24gw7xrcyBtaXMgdsO1aW1hbGRhYiBgZ2dwbG90MmAgZ3JhYWZpa3VpZCBrb2trdSBwYW5uYS4KCkVubmUsIGt1aSBsw6RoZW1lIGBwYXRjaHdvcmtgLWkgZW5kYSBqdXVyZGUgdmFhdGFtZSDDvGh0ZSBrYXN1bGlra3UgbmlwcGkuIE5pbWVsdCBvbiB2w7VpbWFsaWsgZ2dwbG90IGdyYWFmaWsgbXV1dHVqYW5hIHNhbHZldGFkYS4gSm9vbmlzdGF0YWtzZSBzZWUgYWxsZXMgc2lpcyBrdWkgbXV1dHVqYSB2w6TDpHJ0dXMgb24gdmFqYSB2w6RsamEgdHLDvGtraWRhLgoKYGBge3J9CnAgPSBnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jLCB5ID0gdW5lbXBsb3ltZW50X3JhdGUsIGNvbG91ciA9IFBvdmVydHlfZmFjdG9yKSkgKwogIGdlb21fcG9pbnQoKQoKcApwICsgdGhlbWVfYncoKQpgYGAKCkxvZW1lIHNpc3NlIHBha2V0aSBwYXRjaHdvcmsgamEgZGVmaW5lZXJpbWUga29sbSBncmFhZmlrdXQgbWlkYSBrb21iaW5lZXJpbWEgaGFrYXRhLgoKYGBge3J9CmxpYnJhcnkocGF0Y2h3b3JrKQoKcDEgPSBnZ3Bsb3QobGlubmFkLCBhZXMoeCA9IHBlcl9jYXBpdGFfaW5jKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGdndGl0bGUoIlBsb3QgMSIpCnAyID0gZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBwZXJfY2FwaXRhX2luYywgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBjb2xvdXIgPSBQb3ZlcnR5X2ZhY3RvcikpICsKICBnZW9tX3BvaW50KCkgKwogIGdndGl0bGUoIlBsb3QgMiIpCnAzID0gZ2dwbG90KGxpbm5hZCwgYWVzKHggPSBTdGF0ZSwgeSA9IHVuZW1wbG95bWVudF9yYXRlLCBmaWxsID0gU3RhdGUpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdndGl0bGUoIlBsb3QgMyIpCgoKcDEKcDIKcDMKYGBgCgpQYXRjaHdvcmtpcyB0ZWhha3NlIGthIGdyYWFmaWt1dGVnYSAidGVodGVpZCIuIFNlbGxla3MsIGV0IGdyYWFmaWt1aWQga8O1cnZ1dGkgcGFubmEgb24gdGVoZSBgfGAuCgpgYGB7cn0KcDEgfCBwMiAgCmBgYAoKw5xrc3RlaXNlIGFsbGEgc2FhYiBwYW5uYSBncmFhZmlrdWlkIHRlaHRlZ2EgYC9gIC4KCmBgYHtyfQpwMS9wMgpgYGAKClRlaHRlaWQgc2FhYiBrYSBrb21iaW5lZXJpZGEsIHNpaXMgdHVsZWIgdMOkaGVsZXBhbnUganVodGlkYSB0ZWhldGUgasOkcmpla29ycmFsZQoKYGBge3J9CnAxIHwgcDIgLyBwMwpgYGAKCmBgYHtyfQoocDEgfCBwMikgLyBwMwpgYGAKClNlbGxla3MsIGV0IHBpbHRpZGUgcGFpZ3V0dXN0IHBhcmVtaW5pIGtvbnRyb2xsaWRhIG9uIGZ1bmt0c2lvb24gYHBsb3RfbGF5b3V0YCwgbWlsbGVnYSBzYWFiIGpvb25pc2UgZXJpbmV2YWlkIGFzcGVrdGUgbXV1dGEuIE7DpGl0ZWtzIGBoZWlnaHRzYCBwYXJhbWVldGVyIHbDtWltYWxkYWIgbXV1dGEgcGlsdGlkZSBzdWh0ZWxpc2kga8O1cmd1c2VpZC4KCmBgYHtyfQpwMSAvIHAyIC8gcDMgKyBwbG90X2xheW91dChoZWlnaHRzID0gYygyLCAyLCA0KSkKYGBgCgpBcmd1bWVudCB3aWR0aHMgdMO2w7Z0YWIgc2FtYSBtb29kaS4KCmBgYHtyfQoocDEgfCBwMiB8IHAzKSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwgMiwgNCkpCmBgYAoKRWVsbWluZSBwaWx0IGrDpGkga29sZSBzZXN0IHZhc3RhdmF0ZSBsYWl1c3RlZ2Egb24gZ3JhYWZpa3V0ZSBhbmRtZWlkIG7DpGl0YXZhZCBwYW5lZWxpZC4gS3VuYSBrYWhlbCBncmFhZmlrdWwgb24gYWdhIGxlZ2VuZCwgc2lpcyBuZW5kZSBsYWl1c3QgYXJ2ZXNzZSBlaSB2w7VldGEuIEvDvGxsIGFnYSBvbiB2w7VpbWFsaWsgYXJndW1lbmRpZ2EgZ3VpZGVzIGvDtWlraWRlbHQgcGlsdGlkZWx0IGxlZ2VuZGlkIGtva2t1IGtvZ3VkYS4KCmBgYHtyfQoocDEgfCBwMiB8IHAzKSArIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMiwgMiwgNCksIGd1aWRlcyA9ICJjb2xsZWN0IikKYGBgCgpQYWtldGlzIHBhdGNod29yayBvbiB2ZWVsIHBhbGp1IHbDtWltYWx1c2kgamEgdGFzdWIgdXVyaWRhIHBha2V0aSBrb2R1bGVodGUgPGh0dHBzOi8vZ2l0aHViLmNvbS90aG9tYXNwODUvcGF0Y2h3b3JrPiBqYSBzZWFsIHZpaWRhdHVkIMO1cGV0dXNpLgoKIyMjIyDDnGxlc2FuZGVkCgotICAgUHJvb3ZpZ2UgdGVraXRhZGEgasOkcmduZXYgcGlsdAoKIVtdKGltYWdlcy9TY3JlZW5zaG90IDIwMjEtMDItMjggYXQgMTYuMTguMjIucG5nKQpgYGB7cn0KcDEgLyAocDIgfCBwMykgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDQsIDIsIDIpLCBndWlkZXMgPSAiY29sbGVjdCIpCmBgYAoKCiMjIGdncGxvdDItZ2EgZ3JhYWZpa3V0ZSBqb29uaXN0YW1pc2UgaGFyanV0YW1pbmUKClNlbGxlIGphIGVlbG1pc2UgcHJha3Rpa3VtaSBww7VoamFsIHBlYWtzIG9sdWxpc2VtYWQgb3NrdXNlZCBnZ3Bsb3QyIGthc3V0YW1pc2VrcyBvbGVtYXMgb2xlbWEuIE7DvMO8ZCBwcm9vdmltZSBuZWlkIHJha2VuZGFkYSwga2FzdXRhZGVzIGthIHRlYWRtaXNpIHRlaXNlc3QgbG9lbmd1c3QsIGt1cyBzYWkgdHV0dnVzdGF0dWQgZ3JhYWZpa3V0ZSB2YWxpbWlzZSBww7VoaW3DtXR0ZWlkIHTDpHBzZW1hbHQuCgpMb2VtZSBzaXNzZSBrw7VpZ2VwZWFsdCBhbmRtZXN0aWt1LCBtaXMga2lyamVsZGFiIHNpaXMgMjAwMCBpbmltZXNlIGtlaGFtYXNzaSBpbmRla3NlaWQgamEganVodXNsaWt1bCBww6RldmFsIHRlaHR1ZCBzYW1tdWRlIGFydnUuIElnYSBpbmltZXNlIGtvaHRhIG9uIGthIGFudHVkIHN1Z3UsIHZhbnVzIGphIHZhbnVzZWdydXBwLiBMb2VtZSBhbmRtZXN0aWt1IHNpc3NlLgoKYGBge3J9CmxvYWQoImJtaS5SRGF0YSIsIHZlcmJvc2UgPSBUKQoKYm1pCmBgYAoKSWdhIMO8bGVzYW5kZSBwdWh1bCB0YXN1YiBwcm9vdmlkYSBlcmluZXZhaWQgdmFyaWFudGUgamEgbcO1ZWxkYSBtaWxsaW5lIHTDtsO2dGFiIGFudHVkIG9sdWtvcnJhcyBwYXJlbWluaSBqYSBtaWtzLiBNZWVsZGV0dWxldHVzZWtzLCBzaWluIG9uIG9sdWxpc2VtYWQga8Okc3VkIG1pZGEgdmFqYSB2w7VpYiBtaW5uYQoKLSAgIGBnZW9tX3BvaW50YAoKLSAgIGBnZW9tX2hpc3RvZ3JhbWAKCi0gICBgZ2VvbV9iYXJgCgotICAgYGdlb21fYm94cGxvdGAKCi0gICBgZ2VvbV9kZW5zaXR5YAoKLSAgIGBnZW9tX3Zpb2xpbmAKCi0gICBgZ2VvbV9zbW9vdGhgCgotICAgYGZhY2V0X2dyaWRgCgojIyMjIMOcbGVzYW5kZWQKCi0gICBNaWxsaW5lIHRlaHR1ZCBzYW1tdWRlIGphb3R1cz8gTWlsbGlzdCBnZW9tZWV0cmlsaXN0IGVzaXR1c3QgdsO1aWIgc2VsbGUgdXVyaW1pc2VrcyBrYXN1dGFkYT8KCi0gICBNaWxsaW5lIG9uIHRlaHR1ZCBzYW1tdWRlIGphb3R1cyBzdWd1ZGUga2F1cGE/IFZpaGplZDoKCiAgICAtICAgZXQgam9vbmlzdGFkYSBoaXN0b2dyYW1taWQgw7xrc3RlaXNlIHBlYWxlIHRhc3ViIHBhbm5hIGBwb3NpdGlvbiA9ICJpZGVudGl0eSJgCgogICAgLSAgIGFyZ3VtZW50IGBhbHBoYWAga29udHJvbGxpYiB2w6RydmlkZSBsw6RiaXBhaXN0dnVzdAoKLSAgIEt1bW1hIHNvbyBlc2luZGFqYWQgdGVldmFkIG1lZGlhYW5pcyB2w6RoZW0gc2FtbXVzaWQ/CgotICAgVGVlIGzDpGJpIHNlZSBzYW1hIHbDtXJkbHVzIHZhbnVzZWdydXBwaWRlIGthdXBhLiBLYXMgasOkcmVsZHVzIG9uIHNhbWE/CgotICAgVmFhdGEgdmFudXNlZ3J1cHBpZGUgYXJ2dWt1c3Qgc3VndWRlIGthdXBhLiBLYXMgamFvdHVzIG9uIHNhcm5hbmUgdsO1aSBlcmluZXY/CgotICAgS2FzIHZhbnVzZSBqYSB0ZWh0dWQgc2FtbXVkZSB2YWhlbCBvbiBzZW9zPyBLYXMgc2VvcyB0dW5kdWIgbGluZWFhcm5lPwoKLSAgIE1pbGxpbmUgb24gc2VvcyBrZWhhbWFzc2kgaW5kZWtzaSBqYSBzYW1tdWRlIHZhaGVsPyBLYXMgc2VvcyBvbiBsaW5lYWFybmUgamEgdsO1aSBvbiB0ZWd1IG1pbGxlZ2kga2VlcnVrYW1hZ2E/CgojIyBLb2R1bmUgw7xsZXNhbm5lCgpNZWlsIG9uIGFuZG1lc3RpayBlcmluZXZhdGUgbWFhaWxtYSByaWlraWRlIG5pbmcgbmVuZGUgc290c2lhYWxzZXRlIGluZGVrc2l0ZSBrb2h0YS4gU2VlIGFuZG1lc3RpayBvbiBmYWlsaXMgYGNvdW50cmllcy5SRGF0YWAgbWlzIG9uIGthYXNhcyBwcmFrdGlrdW1pIG1hdGVyamFsaWRlZ2EuIFNlbGxlbCBhbmRtZXN0aWt1bCB0dWxla3MgdXVyaWRhIGvDvHNpbXVzdCwga2FzIGphIG1pbGxpbmUgb24gc2VvcyBsYXN0ZSBhcnZ1bCBuYWlzZSBrb2h0YSAoYGNoaWxkX3Blcl93b21hbmApIG9vZGF0YXZhIGVsdWVhZ2EgKGBsaWZlX2V4cGVjdGFuY3lgKS4gU2VhbGp1dXJlcyB0dWxla3MgcGlsZGlsIGFydmVzc2UgdsO1dHRhIGthIHJpaWtpZGUgcG9wdWxhdHNpb29uaSAoYHBvcHVsYXRpb25fdG90YWxgKSwgbWFhaWxtYWphZ3UgKGByZWdpb25gKSBuaW5nIGphb3R1c3Qgc2lzc2V0dWxla3UgasOkcmdpIChgaW5jb21lX2dyb3Vwc2ApLiBLw7VpayBtdXV0dWphZCB2w7VpYiBwYW5uYSDDvGhlbGUgcGlsZGlsZSB2w7VpIHbDtWliIGtvbWJpbmVlcmlkYSBrYSBtaXRtZXN0IHBhbmVsbGlzdCBwYXRjaHdvcmtpIGthc3V0YWRlcy4gS3VuYSBhbmRtZWQgb24ga2VlcnVrYWQgdsO1aWIgcGlsZGkgc2FsdmVzdGFkYSBzdXVyZW1hbmEgKGthc3V0YWRlcyBrw6Rza3UgYGdnc2F2ZWAgamEgYXJndW1lbnRlIGBoZWlnaHRgIGphIGB3aWR0aGApLCBldCBrw7VpZ2VsIHZhamFsaWt1bCBwaWlzYXZhbHQgcnV1bWkgb2xla3MuCgpFc2l0YWRhIHR1bGViIGdyYWFmaWt1dCBnZW5lcmVlcml2ICoqa29vZCoqIGphIGthIG3DtW5lIGxhdXNlbGluZSAqKmrDpHJlbGR1cyoqLCBtaWxsZSB0ZSBwaWxkaWx0IG9sZXRlIHbDpGxqYSBsdWdlbnVkLgoKYGBge3J9CmxvYWQoImNvdW50cmllcy5SRGF0YSIsIHZlcmJvc2UgPSBUKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHNqbWlzYykKCiNwb3B1bGF0c2lvb25pZCBrdmFudGlpbGlkZSBww7VoamFsIDVrcyBrYXRlZ29vcmlha3MKY291bnRyaWVzJHBvcF9ncm91cGVkIDwtIHNwbGl0X3Zhcihjb3VudHJpZXMkcG9wdWxhdGlvbl90b3RhbCwgbiA9IDQpIAoKI2VyYWxkdXNrb2hhZApzcGxpdHMgPC0gcHJldHR5TnVtKHF1YW50aWxlKGNvdW50cmllcyRwb3B1bGF0aW9uX3RvdGFsLCBjKC4yNSwuNTAsLjc1LDEpLCBuYW1lcyA9IEZBTFNFKSxiaWcubWFyaz0iLCIsIHNjaWVudGlmaWMgPSBGQUxTRSkgCgojS2F0ZWdvb3JpYXRlIG5pbWVkCm5pbWVkIDwtIGMocGFzdGUwKCIwLSIsc3BsaXRzWzFdKSwKICAgICAgICAgICBwYXN0ZTAoc3BsaXRzWzFdLCItIixzcGxpdHNbMl0pLAogICAgICAgICAgIHBhc3RlMChzcGxpdHNbMl0sIi0iLHNwbGl0c1szXSksCiAgICAgICAgICAgcGFzdGUwKHNwbGl0c1szXSwiLSIsc3BsaXRzWzRdKSkKCmNvdW50cmllcyRwb3BfZ3JvdXBlZCA8LSBmYWN0b3IoY291bnRyaWVzJHBvcF9ncm91cGVkLCBsYWJlbHMgPSBuaW1lZCkgCgpnZ3Bsb3QoY291bnRyaWVzLCBhZXMoeD1jaGlsZF9wZXJfd29tYW4sIHkgPSBsaWZlX2V4cGVjdGFuY3kpKSsKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpKwogIHhsYWIobGFiZWwgPSAiTGFwc2kgbmFpc2Uga29odGEiKSsKICB5bGFiKGxhYmVsID0gIk9vZGF0YXYgZWx1aWdhIikrCiAgdGhlbWVfYncoKQoKICBnZ3Bsb3QoY291bnRyaWVzLCBhZXMoeD1jaGlsZF9wZXJfd29tYW4sIHkgPSBsaWZlX2V4cGVjdGFuY3ksIGNvbG9yID0gaW5jb21lX2dyb3VwcykpKwogICAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSByZWdpb24pKSsKICAgIGdlb21fc21vb3RoKGFlcyhmaWxsID0gaW5jb21lX2dyb3VwcyksIG1ldGhvZD0ibG0iKSsKICAgIHhsYWIobGFiZWwgPSAiTGFwc2kgbmFpc2Uga29odGEiKSsKICAgIHlsYWIobGFiZWwgPSAiT29kYXRhdiBlbHVpZ2EiKSsKICAgIHNjYWxlX2NvbG91cl9icmV3ZXIodHlwZSA9ICJzZXEiLCBwYWxldHRlID0gMikrCiAgICBzY2FsZV9maWxsX2JyZXdlcih0eXBlID0gInNlcSIsIHBhbGV0dGUgPSAyKSsKICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJibGFjayIpKQoKZ2dwbG90KGNvdW50cmllcywgYWVzKHg9Y2hpbGRfcGVyX3dvbWFuLCB5ID0gbGlmZV9leHBlY3RhbmN5LCBjb2xvciA9IHJlZ2lvbikpKwogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBwb3B1bGF0aW9uX3RvdGFsKSkrCiAgZ2VvbV9zbW9vdGgoYWVzKGZpbGwgPSByZWdpb24pLCBtZXRob2Q9ImxtIikKCmdncGxvdChjb3VudHJpZXMsIGFlcyh4PWNoaWxkX3Blcl93b21hbiwgeSA9IGxpZmVfZXhwZWN0YW5jeSwgY29sb3IgPSBwb3BfZ3JvdXBlZCkpKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX3Ntb290aChhZXMoZmlsbCA9IHBvcF9ncm91cGVkKSwgbWV0aG9kPSJsbSIpCmBgYAoKCgoKSGluZGFtZSBqw6RyZ25ldmFpZCBhc3Bla3RlCgotICAgSsOkcmVsZHVzZSBhc2pha29oYXN1cyBqYSBrdWkgbGlodG5lIG9uIHNlZGEgcGlsZGlnYSBrb2trdSB2aWlhCgotICAgR3JhYWZpa3UodGUpIGpvb25pc3RhbWlzZWwgdGVodHVkIHZhbGlrdXRlIGFzamFrb2hhc3VzCgotICAgR3JhYWZpbGlzZWQgZGV0YWlsaWQgamEgbmVuZGUgdmFsaWsKCiAgICAtICAgVsOkcnZpc2thYWxhZAoKICAgIC0gICBEaXNrcmVldHNldGUgbXV1dHVqYXRlIGrDpHJqZWtvcmQKCiAgICAtICAgS8O1aWsgdGVrc3RpZCBwaWxkaWwgdsO1aWtzaWQgb2xsYSBrZXJnZXN0aSBsb2V0YXZhZCAoc3V1cnRlIHTDpGh0ZWRlZ2EsIGdyYW1tYXRpbGlzZWx0IGtvcnJla3RzZWQsIHBpaXNhdmFsdCBraXJqZWxkYXZhZCkK